// miniloop, a simple live looper
//
// Copyright (C) 2007 Nick Thomas
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the <organization> nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NICK THOMAS ``AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL NICK THOMAS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <dirent.h>
#include <unistd.h>
#include <sstream>
#include "Config.hpp"
#include "FileBrowserWindow.hpp"
using namespace miniloop;

FileBrowserWindow::FileBrowserWindow()
    : m_refresh_button("Refresh")
{
    m_model = Gtk::TreeStore::create(m_columns);
    m_model->set_sort_column(m_columns.m_name, Gtk::SORT_ASCENDING);
    refresh();

    std::list<Gtk::TargetEntry> dnd_targets;
    dnd_targets.push_back(Gtk::TargetEntry("STRING"));
    dnd_targets.push_back(Gtk::TargetEntry("text/plain"));

    m_view.set_model(m_model);
    m_view.append_column("Filename", m_columns.m_name);
    m_view.append_column("Use Count", m_columns.m_use_count);
    m_view.get_column(0)->set_expand(true);
    m_view.get_column(1)->set_expand(false);
    m_view.set_headers_visible(false);
    m_view.enable_model_drag_source(dnd_targets);
    m_view.signal_drag_data_get().connect(sigc::mem_fun(*this,
		&FileBrowserWindow::on_drag_data_get));

    m_browser_window.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
    m_browser_window.add(m_view);

    m_refresh_button.signal_clicked().connect
	(sigc::mem_fun(this, &FileBrowserWindow::refresh));

    m_vbox.pack_start(m_browser_window);
    m_vbox.pack_start(m_refresh_button, Gtk::PACK_SHRINK);
    add(m_vbox);

    set_title("miniloop - files");
    resize(200,800);
    show_all_children();
}

void FileBrowserWindow::refresh()
{
    m_model->clear();
    list_directory(m_model->children(), g_config.loop_dir);
}

void FileBrowserWindow::list_directory(Gtk::TreeModel::Children node,
Glib::ustring dir)
{
    DIR *dir_handle = opendir(dir.c_str());
    struct dirent *entry;

    if (!dir_handle) {
	printf("Error opening %s for reading: %s\n", dir.c_str(),
	       	strerror(errno));
	return;
    }

    while ((entry = readdir(dir_handle))) {
	Glib::ustring name = entry->d_name;

	if (name == "." || name == "..") {
	    continue;
	}

	Glib::ustring path;
	path.append(dir).append("/").append(name);

        Gtk::TreeModel::Row row = *m_model->append(node);
        row[m_columns.m_name] = name;
	row[m_columns.m_use_count] = 0;

	struct stat info;
	if (stat(path.c_str(), &info) < 0) {
	    printf("Error: could not stat %s: %s\n", path.c_str(),
		    strerror(errno));
	}

        if (S_ISDIR(info.st_mode)) {
	    list_directory(row.children(), path);
        }
    }

    closedir(dir_handle);
}

void FileBrowserWindow::on_drag_data_get(
	const Glib::RefPtr<Gdk::DragContext> &context,
	Gtk::SelectionData &selection_data, guint, guint)
{
    std::vector<Gtk::TreeModel::Path> selection =
	m_view.get_selection()->get_selected_rows();
    Gtk::TreeModel::Path path = selection[0];

    Glib::ustring file = g_config.loop_dir;
    Gtk::TreeNodeChildren children = m_model->children();

    for (int i = 0; i < path.get_depth(); i++) {
	file += "/";
	Gtk::TreeModel::Row row = children[path[i]];
	file += row[m_columns.m_name];
	row[m_columns.m_use_count] = row[m_columns.m_use_count] + 1;
	children = row.children();
    }

    selection_data.set(selection_data.get_target(), 8,
	    (const guchar *)file.c_str(),
	    file.length());
}
